from __future__ import absolute_import
import logging
import random
import re
import os
import traceback
from collections import namedtuple
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.utils import timezone
from django.db.models import F, Q
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from obs import RestoreTier, SetObjectMetadataHeader, PutObjectHeader
from data_mgt.models import SceneData, DataDownloadInfo, ObsAsyncJobStatus, AnonymizedData
from data_mgt.serializer import SceneDataSerializer
from data_mgt.tasks import async_count_scene_data, async_delete_scene_data
from monitor.models import MonitorRealTimeInfo, MonitorAlarm
from conf.conf import obs_bucket_name
from common.obs_tools import obs_client, object_restore_status, get_job_type
from common.ploto_enum import CommonStatuEnum, DataStatuEnum
from common.ploto_response import PlotoResponse
from common.tools import auth_request, fill_filter_data, set_header

logger = logging.getLogger(__name__)


class SceneDataHandler(APIView):
    """
    单个场景数据对象的操作类  场景数据是文件夹
    """

    @auth_request
    def get(self, request, pk):
        """
        获取单条场景数据的详情
        param request,pk
        return: data + list_tag + playback_url
        1、获取pk对应的数据obj
        2、并获取对应的tag字段信息，返回list_tag，方便前端更新此字段
        3、针对MP4文件获取对应的可授权的播放链接  传回前端播放
        """
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.view_scenedata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        obj = SceneData.objects.get(id=pk)
        list_tag = obj.tag.split('|')
        if None is re.match(r'^obs://\S+/.+[^/]+$', obj.url):
            logger.warning("场景数据url无效")
            response.code = DataStatuEnum.SCENE_URL_EXCEPTION.code
            response.msg = DataStatuEnum.SCENE_URL_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
        object_url = obj.url
        bucket_name = object_url.split("/")[2]
        object_key_path = object_url.split("/", 3)[-1]
        resp = obs_client.listObjects(bucket_name, prefix=object_key_path)
        for content in resp.body.contents:
            if ".mp4" in content.key:
                playback_key = content.key
        try:
            resp = obs_client.createSignedUrl('GET', bucket_name, playback_key, expires=3600)
            serializer = SceneDataSerializer(obj)
            response.data = serializer.data
            response.data["list_tag"] = list_tag
            response.data["playback_url"] = resp.signedUrl
            return Response(response.dict, status=status.HTTP_200_OK)
        except Exception as e:
            logger.error("序列化或调用obs生成链接异常:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def post(self, request):
        """
        场景数据新增接口
        :param request:
        :return: data  新增数据信息
        1、获取request写入的数据信息
        2、保存数据信息，并返回
        """
        response = PlotoResponse()
        params = request.data
        if isinstance(params, dict):
            params = [params]
        data_list = []
        for data in params:
            try:
                from_data = AnonymizedData.objects.filter(uuid=data.get('from_uuid', ''))[0]
            except Exception as e:
                logger.error("原始数据查询出错:%s, %s", repr(e), traceback.format_exc())
                response.code = CommonStatuEnum.INTERNAL_ERROR.code
                response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                response.data["Error: "] = repr(e)
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            source_key_name = data.get('url').split('/', 3)[-1]
            des_bucket_name = obs_bucket_name
            des_key_name = "scene/{}".format((source_key_name.split('/', 1)[-1]))
            key_list = des_key_name.split('.')
            key_list[-2] = '{}_{}'.format(key_list[-2], str(random.randint(1, 3000)))
            des_key_name = '.'.join(key_list)
            headers = PutObjectHeader()
            headers.storageClass = "STANDARD"
            filepath = os.path.abspath(os.path.dirname(os.getcwd()))
            filepath = '{}/initutils/ploto_file/scene'.format(filepath)
            dir_list = os.listdir(filepath)
            filepath = '{}/{}'.format(filepath, dir_list[0])
            filepath = filepath.replace('\\', '/')
            try:
                obs_client.putFile(des_bucket_name, des_key_name, filepath, headers=headers)
            except Exception as e:
                logger.error("上传obs数据失败%s, %s",  repr(e), traceback.format_exc())
                response.code = CommonStatuEnum.INTERNAL_ERROR.code
                response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            data_list.append(SceneData(name=data.get('name', ''),
                                       size=data.get('size', 0),
                                       car_id=data.get('car_id', ''),
                                       data_type=data.get('data_type', 0),
                                       region=data.get('region', ''),
                                       url=des_bucket_name + des_bucket_name,
                                       is_delete=data.get('is_delete', False),
                                       tag=data.get('tag', ''),
                                       remark=data.get('remark', ''),
                                       collect_time=data.get('collect_time', ''),
                                       storage_type=data.get('storage_type', 0),
                                       data_status=0,
                                       scenario_id=data.get('scenario_id', 0),
                                       from_data_id=from_data.id))
            async_count_scene_data.delay(scenario_id=data.get('scenario_id', ''),
                                         size=data.get('size', 0),
                                         city=data.get('region', ''))
            try:
                SceneData.objects.bulk_create(data_list)
            except Exception as e:
                logger.error("数据库更新失败:%s, %s", repr(e), traceback.format_exc())
                response.code = CommonStatuEnum.INTERNAL_ERROR.code
                response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        response.code = CommonStatuEnum.OK.code
        response.msg = CommonStatuEnum.OK.msg
        return Response(response.dict, status=status.HTTP_200_OK)

    def put(self, request, pk):
        """
        单条场景数据修改
        :param request
        :param pk
        :return: data  新增数据信息
        1、获取指定id的obj信息
        2、获取修改的操作  针对取回/归档/修改tag/修改其他字段
        2.1 前端传了tag字段，则表示更新了tag
           a、用. join()连接前端传的数据
           b、并更新到对应的数据字段
           c、并将更新的数据返回给前端更新
        2.2 修改其他字段：通过序列化的方式更新修改的字段
        2.3 取回和归档的逻辑参考_retrieval和_save_cold流程
        """
        params = request.data
        response = PlotoResponse()
        # 修改 tag字段
        if not request.user.has_perm('data_mgt.change_scenedata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        tag = params.get('tag', '')
        remark = params.get('remark')
        # 只有tag和remark能更新
        if tag:
            tag_str = "|".join(tag)
            resp = SceneData.objects.filter(id=pk).update(tag=tag_str)
            if resp != 1:
                logger.error("数据库更新tag失败")
                response.code = CommonStatuEnum.INTERNAL_ERROR.code
                response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        if remark:
            resp = SceneData.objects.filter(id=pk).update(remark=remark)
            if resp != 1:
                logger.error("数据库更新remark失败")
                response.code = CommonStatuEnum.INTERNAL_ERROR.code
                response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        return Response(response.dict, status=status.HTTP_201_CREATED)

    def delete(self, request, pk):
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.delete_scenedata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        resp = SceneData.objects.filter(id=pk).update(is_delete=True)
        if resp != 1:
            logger.error("场景数据表更新失败")
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        async_delete_scene_data.delay(pk)  # 异步改变SceneDataCount和monitor
        delete_status = do_delete(pk)
        if delete_status is False:
            logger.error("obs数据删除失败")
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        return Response(response.dict, status=status.HTTP_204_NO_CONTENT)


class BatchSceneData(APIView):

    @auth_request
    def get(self, request):
        """
        批量场景数据获取
        :param request
        :return: data
        1、获取分页标记信息
        2、指定部分字段为模糊匹配搜索以及按区间搜索的字段
        3、获取根据过滤条件得到的数据信息
        4、序列化分页数据，返回给数据信息给前端
        """
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.view_scenedata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        # 重写View中的get方法
        params = request.query_params.dict()
        # 获取分页标记信息,默认为1,page_size 默认为10
        page = int(params.get('page', 1))
        page_size = int(params.get('page_size', 10))
        filter_data = fill_filter_data(params)
        scene_data_list = SceneData.objects.filter(**filter_data)
        #  没有数据提示 传空数据出去
        if scene_data_list.count() == 0:
            return Response({'message': 'data is empty!', "data": []}, status=status.HTTP_200_OK)

        paginator = Paginator(scene_data_list, page_size)
        try:
            page_scene_data_list = paginator.page(page)
        except PageNotAnInteger:
            page_scene_data_list = paginator.page(1)
        except EmptyPage:
            page_scene_data_list = paginator.page(paginator.num_pages)
        try:
            scene_data = SceneDataSerializer(instance=page_scene_data_list, many=True)
            response.data["data_list"] = scene_data.data
            response.data["count"] = paginator.count
            return Response(response.dict, status=status.HTTP_200_OK)
        except Exception as e:
            logger.error("序列化异常:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def delete(self, request):
        """
        批量场景数据修改存储类别
        :param request
        :return: data
        1、获取前端传入的ids信息
        2、根据ids调用数据库的filter 和 update操作
        """
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.delete_scenedata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        id_list = request.POST.get('ids')
        if not id_list:
            response.code = CommonStatuEnum.VALID_EXCEPTION.code
            response.msg = CommonStatuEnum.VALID_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
        delete_id_list = id_list.split(',')
        try:
            SceneData.objects.filter(id__in=delete_id_list).update(is_delete=True)
            for delete_id in delete_id_list:
                delete_status = do_delete(delete_id)
                if delete_status is False:
                    logger.error("obs数据删除失败")
                    response.code = CommonStatuEnum.INTERNAL_ERROR.code
                    response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                    return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            return Response(response.dict, status=status.HTTP_204_NO_CONTENT)
        except Exception as e:
            logger.error("数据库更新失败:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class SceneDataFileHandler(APIView):

    @auth_request
    def get(self, request, pk):
        """
        场景数据文件下载
        :param request
        :param pk
        :return: signedUrl
        1、根据id 信息获取数据库中对心的信息 并解析桶名和对象名  获取对象前缀信息
        2、根据前缀信息  调用obs接口所有的对象信息
        3、轮循所有的对象  分别获取对应的可授权的下载链接
        4、 分别将 对象名和下载链接 放到字典中 返回给前端，前端在点击下载后，会弹出一个对话框 列出所有的对象以及下载链接 供选择下载
        5、同步下载信息到下载信息表中
        6、同步表中的下载次数
        """
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.download_scenedata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        download_dict = {}
        obj = SceneData.objects.filter(id=pk)
        if None is re.match(r'^obs://\S+/.+[^/]+$', obj[0].url):
            logger.warning("场景数据url无效")
            response.code = DataStatuEnum.SCENE_URL_EXCEPTION.code
            response.msg = DataStatuEnum.SCENE_URL_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
        bucket_name = obj[0].url.split("/")[2]
        object_key = obj[0].url.split("/")[-1]
        prefix = obj[0].url.split("/", 3)[-1]
        resp = obs_client.listObjects(bucket_name, prefix=prefix)
        # 获取list失败的异常处理
        if resp.status >= 300:
            logger.error("获取场景对象列表失败:%s, %s", resp.errorCode, resp.errorMessage)
            response.msg = DataStatuEnum.GET_SCENE_LIST_EXCEPTION.msg
            response.code = DataStatuEnum.GET_SCENE_LIST_EXCEPTION.code
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
        # 遍历文件夹下的数据
        for content in resp.body.contents:
            # 当前规避：归档存储   恢复中和未恢复  不能下载
            if obj[0].storage_type == 2:
                restore_status = object_restore_status(bucket_name, content.key)
                if restore_status in {'no_restored', 'restoring'}:
                    alarm_details = str(self.request.user) + "用户下载场景数据文件" + object_key + "失败"
                    MonitorAlarm.objects.create(alarm_time=timezone.now(), alarm_content='下载异常',
                                                alarm_details=alarm_details, level=0)
                    response.code = DataStatuEnum.DOWNLOAD_EXCEPTION.code
                    response.msg = DataStatuEnum.DOWNLOAD_EXCEPTION.msg
                    return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
            headers = SetObjectMetadataHeader()
            headers.contentType = "application/octet-stream"
            # mp4文件默认为播放，需要添加contentType就可以直接下载不播放
            res = obs_client.setObjectMetadata(bucket_name, content.key, headers=headers)
            if res.status >= 300:
                logger.error("设置对象元数据失败:%s, %s", res.errorCode, res.errorMessage)
                response.code = DataStatuEnum.SET_METADATA_EXCEPTION.code
                response.msg = DataStatuEnum.SET_METADATA_EXCEPTION.msg
                return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
            try:
                resp = obs_client.createSignedUrl('GET', bucket_name, content.key, expires=3600)
            except Exception as e:
                alarm_details = str(self.request.user) + "用户下载场景数据文件" + object_key + "失败"
                try:
                    MonitorAlarm.objects.create(alarm_time=timezone.now(), alarm_content='下载异常',
                                                alarm_details=alarm_details, level=0)
                except Exception as e:
                    logger.error("告警数据表插入数据失败: %s, %s", repr(e), traceback.format_exc())
                logger.error("创建下载url:%s, %s", repr(e), traceback.format_exc())
                response.code = DataStatuEnum.GET_DOWNLOAD_URL_EXCEPTION.code
                response.msg = DataStatuEnum.GET_DOWNLOAD_URL_EXCEPTION.msg
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            download_key = content.key.split("/")[-1]
            download_dict[download_key] = resp.signedUrl
        try:
            # 同步下载数据到数据下载信息表中
            DataDownloadInfo.objects.create(data_id=pk, data_type=1, data_version=obj[0].version,
                                            user=self.request.user)
            info_content = str(self.request.user) + "用户下载场景数据文件" + object_key
            MonitorRealTimeInfo.objects.create(create_time=timezone.now(), info_content=info_content)
            # 同步下载次数
            SceneData.objects.filter(id=pk).update(download_times=F('download_times') + 1)
            response.data["data"] = download_dict
            return Response(response.dict, status=status.HTTP_200_OK)
        except Exception as e:
            logger.error("数据下载信息表同步失败:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class SceneDataRestore(APIView):
    SceneParam = \
        namedtuple('AnonymizeParam', ['days_num', 'fail_dict', 'obj_list', 'success_object', 'tier'])

    def post(self, request):
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.restore_anonymizeddata'):
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        params = request.data
        days_num = params.get("days_num", 30)
        rate = params.get("rate", 'STANDARD')
        id_list = params.get('ids', [])
        fail_dict = {}
        success_object = []
        tier = RestoreTier.EXPEDITED if rate == 'EXPEDITED' else RestoreTier.STANDARD
        obj_list = SceneData.objects.filter(id__in=id_list)
        if obj_list is None:
            response.code = DataStatuEnum.NOT_EXIST_EXCEPTION.code
            response.msg = DataStatuEnum.NOT_EXIST_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_404_NOT_FOUND)
        scene_param = self.SceneParam(days_num=days_num, fail_dict=fail_dict, obj_list=obj_list,
                                      success_object=success_object, tier=tier)
        self._do_restore(scene_param)
        # 对于取回的成功的对象 需要修改其恢复状态  当前设置为恢复中 规避方法下一次操作的时候先查（恢复中->已恢复）
        if success_object:
            if fail_dict:
                response.msg = DataStatuEnum.RESTORE_EXCEPTIOM.msg
                response.code = DataStatuEnum.RESTORE_EXCEPTIOM.code
                response.data = fail_dict
                return Response(response.dict, status=status.HTTP_206_PARTIAL_CONTENT)
            else:
                return Response(response.dict, status=status.HTTP_200_OK)
        else:
            response.msg = DataStatuEnum.RESTORE_EXCEPTIOM.msg
            response.code = DataStatuEnum.RESTORE_EXCEPTIOM.code
            response.data = fail_dict
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)

    def _do_restore(self, scene_param):
        days_num, fail_dict, obj_list, success_object, tier = scene_param
        for obj in obj_list:
            result = True
            if None is re.match(r'^obs://\S+/.+[^/]+$', obj.url):
                fail_dict[obj.name] = DataStatuEnum.ANONYMIZE_URL_EXCEPTION.msg
                logger.warning("场景数据%s url无效", obj.name)
                continue
            bucket_name = obj.url.split("/")[2]
            object_key = obj.url.split("/")[-1]
            object_key_path = obj.url.split("/", 3)[-1]
            prefix = '{}/{}'.format(object_key_path, object_key)
            resp = obs_client.listObjects(bucket_name, prefix=prefix)
            # 获取list失败的异常处理
            if resp.status >= 300:
                logger.error("获取场景对象列表失败:%s, %s", resp.errorCode, resp.errorMessage)
                fail_dict[obj.name] = DataStatuEnum.GET_SCENE_LIST_EXCEPTION.msg
                continue
            for content in resp.body.contents:
                restore_status = object_restore_status(bucket_name, content.key)
                if restore_status in {'no_restored', 'restored'}:
                    resp = obs_client.restoreObject(bucket_name, content.key, days_num, tier)
                    if resp.status >= 300:
                        fail_dict[obj.name] = resp.errorMessage
                        result = False
                        break
                    try:
                        ObsAsyncJobStatus.objects.create(job_id=obj.id, job_data_type=1, job_type=get_job_type(tier),
                                                         job_bucket=bucket_name, job_object=content.key,
                                                         next_run_time=timezone.now())
                    except Exception as e:
                        logger.error("异步任务表新增数据失败: %s, %s", repr(e), traceback.format_exc())
                        fail_dict[obj.name] = CommonStatuEnum.INTERNAL_ERROR.msg
                        result = False
                        break
                else:
                    fail_dict[obj.name] = DataStatuEnum.RESTORING_NOT_ALLOWED.msg
                    result = False
                    break
            # 针对结果进行处理
            if result:
                try:
                    # 对于取回的成功的对象 需要修改其恢复状态  当前设置为恢复中 规避方法下一次操作的时候先查（恢复中->已恢复）
                    SceneData.objects.filter(id=obj.id).update(restoration_status=2)
                except Exception as e:
                    logger.error("脱敏数据表更新失败:%s, %s", repr(e), traceback.format_exc())
                    fail_dict[obj.name] = CommonStatuEnum.INTERNAL_ERROR.msg
                success_object.append(obj.name)


class SceneDataModifyStorageClass(APIView):
    SceneParam = \
        namedtuple('AnonymizeParam', ['fail_dict', 'headers', 'obj_list', 'storage_class', 'success_object'])

    def post(self, request):
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.modify_class_scenedata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        params = request.data
        id_list = params.get('ids', [])
        storage_class = params.get("storage_class")
        headers = SetObjectMetadataHeader()
        set_header(headers, storage_class)
        success_object = []
        fail_dict = {}
        obj_list = SceneData.objects.filter(id__in=id_list)
        if obj_list is None:
            response.code = DataStatuEnum.NOT_EXIST_EXCEPTION.code
            response.msg = DataStatuEnum.NOT_EXIST_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_404_NOT_FOUND)
        scene_param = self.SceneParam(fail_dict=fail_dict, headers=headers, obj_list=obj_list,
                                      storage_class=storage_class, success_object=success_object)
        self._get_modify_result(scene_param)
        if success_object:
            if fail_dict:
                response.code = DataStatuEnum.MODIFY_CLASS_EXCEPTION.code
                response.msg = DataStatuEnum.MODIFY_CLASS_EXCEPTION.msg
                response.data = fail_dict
                return Response(response.dict, status=status.HTTP_206_PARTIAL_CONTENT)
            else:
                return Response(response.dict, status=status.HTTP_200_OK)
        else:
            response.code = DataStatuEnum.MODIFY_CLASS_EXCEPTION.code
            response.msg = DataStatuEnum.MODIFY_CLASS_EXCEPTION.msg
            response.data = fail_dict
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)

    def _get_modify_result(self, scene_param):
        fail_dict, headers, obj_list, storage_class, success_object = scene_param
        for obj in obj_list:
            source_storage_class = obj.storage_type
            result = True
            if None is re.match(r'^obs://\S+/.+[^/]+$', obj.url):
                fail_dict[obj.name] = DataStatuEnum.ANONYMIZE_URL_EXCEPTION.msg
                logger.warning("场景数据数据%s url无效", {obj.name})
                continue
            bucket_name = obj.url.split("/")[2]
            object_key = obj.url.split("/")[-1]
            object_key_path = obj.url.split("/", 3)[-1]
            prefix = '{}/{}'.format(object_key_path, object_key)
            resp = obs_client.listObjects(bucket_name, prefix=prefix)
            # 获取list失败的异常处理
            if resp.status >= 300:
                logger.error("获取场景对象列表失败:%s, %s", resp.errorCode, resp.errorMessage)
                fail_dict[obj.name] = DataStatuEnum.GET_SCENE_LIST_EXCEPTION.msg
                continue
            # 遍历对象目录下的文件
            for content in resp.body.contents:
                # 从归档存储修改为标准存储时 需要判断恢复状态为已恢复  才能操作
                if source_storage_class == 2:
                    restore_status = object_restore_status(bucket_name, content.key)
                    if restore_status == 'restored':
                        resp = obs_client.setObjectMetadata(bucket_name, content.key, headers=headers)
                        if resp.status >= 300:
                            logger.error("设置对象元数据失败:%s, %s", resp.errorCode, resp.errorMessage)
                            fail_dict[obj.name] = DataStatuEnum.SET_METADATA_EXCEPTION.msg
                            result = False
                            break
                    else:
                        fail_dict[obj.name] = DataStatuEnum.MODIFY_CLASS_NOT_ALLOWED.msg
                        result = False
                        break
                else:
                    resp = obs_client.setObjectMetadata(bucket_name, content.key, headers=headers)
                    if resp.status >= 300:
                        logger.error("设置对象元数据失败:%s, %s", resp.errorCode, resp.errorMessage)
                        fail_dict[obj.name] = DataStatuEnum.SET_METADATA_EXCEPTION.msg
                        result = False
                        break
            # 处理场景数据下的对象
            if result:
                try:
                    # 执行成功的id  更新对应的字段  修改为归档存储时 恢复状态为未恢复  修改为其他存储类别 则恢复状态为--
                    if headers.storageClass == 'COLD':
                        SceneData.objects.filter(id=obj.id).update(storage_type=storage_class,
                                                                   restoration_status=1)
                    else:
                        SceneData.objects.filter(id=obj.id).update(storage_type=storage_class,
                                                                   restoration_status=0)
                except Exception as e:
                    logger.error("场景数据表更新失败：%s, %s", repr(e), traceback.format_exc())
                    fail_dict[obj.name] = CommonStatuEnum.INTERNAL_ERROR.msg
                success_object.append(obj.name)


def do_delete(pk):
    obj = SceneData.objects.get(id=pk)
    object_url = obj.url
    bucket_name = object_url.split("/")[2]
    object_key_path = object_url.split("/", 3)[-1]
    resp = obs_client.listObjects(bucket_name, prefix=object_key_path)
    for content in resp.body.contents:
        delete_url = content.key
        delete_resp = obs_client.deleteObject(bucket_name, delete_url)
        if delete_resp.status >= 300:
            return False
    return True
